#include "mainwindow.h"
#include "ui_mainwindow.h"
//##############################################
//##########Public Member Functions#############
//##############################################
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    statusBar = ui->statusBar;
    operationStatus = new QLabel;
    statusBar->addWidget(operationStatus);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::cV2QImage(cv::Mat &image,QScrollArea *scrollArea,QLabel *label)
{
    QImage::Format format;
    if(image.channels() == 3)
        format = QImage::Format_RGB888;
    else
        format = QImage::Format_Indexed8;
    QImage img = QImage((const unsigned char*)(image.data),
                        image.cols,image.rows,
                        image.cols*image.channels(),
                        format);
    label->resize(img.size());
    label->setPixmap(QPixmap::fromImage(img));
    scrollArea->setWidget(label);
    scrollArea->setWidgetResizable(true);
    scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
    scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
    scrollArea->viewport()->setBackgroundRole(QPalette::Mid);
    scrollArea->viewport()->setAutoFillBackground(true);
    scrollArea->show();
}

////执行
std::vector<int> MainWindow::sortedFileNames(QStringList &fiList)
{
    std::vector<int> result;
    for(int i = 0; i < (int)fiList.size(); ++i)  //获取文件名，因此图片文件名只能是数字！
        result.push_back(fiList[i].mid(0,fiList[i].indexOf('.')).toInt());
    std::sort(result.begin(),result.end()); //进行排序
    return result;
}

void MainWindow::viewMat(cv::Mat &mt)
{
    for(int j = 0; j < mt.rows; ++j) {
        for(int k = 0; k < mt.cols; ++k)
            std::cout<<mt.at<float>(j,k)<<" ";
        std::cout<<"\n";
        std::cout<<"####"<<std::endl;
    }
}

void MainWindow::dctOnImage(cv::Mat &image)
{
    //用8*8的矩形划分图像，将每个矩形框的DCT系数作为输入值
    for(int i = 0; i < image.rows; ++i) {
        for(int j = 0; j < image.cols; ++j) {

        }
    }
}
//width与height分别为矩形框的宽和高
void MainWindow::drawRectOnGrayMat(cv::Mat &mt, int width, int height)
{
    for(int i = 8; i < mt.rows; i += height) {
        for(int j = 0; j < mt.cols; ++j) {  //画横线
            mt.at<uchar>(i,j) = 255;
        }
    }
    for(int j = 8; j < mt.cols; j += width) {  //画竖线
        for(int i = 0; i < mt.rows; ++i) {
            mt.at<uchar>(i,j) = 255;
        }
    }
}
//从输入图像找到前景样本的ROI
std::vector<cv::Rect> MainWindow::autoExtractROI(cv::Mat &img)
{
    std::vector<cv::Rect> result;

    return result;
}

int MainWindow::getBlockType(cv::Mat &sampleBlock)
{
    //查找图像块中是否有标记
    //注意，输入的是一幅彩色图像
    for(int i = 0; i < sampleBlock.rows; ++i) {
        for(int j = 0; j < sampleBlock.cols; ++j) {
            if(sampleBlock.at<cv::Vec3b>(i,j)[0] == 0 &&
                    sampleBlock.at<cv::Vec3b>(i,j)[1] == 0 &&
                    sampleBlock.at<cv::Vec3b>(i,j)[2] == 255)   //红的
                return 1;
        }
    }
    return -1;
}
//##############################################
//############Slot Member Functions#############
//##############################################
//选择图片序列
void MainWindow::on_action_triggered()
{
    QString dirName = QFileDialog::getExistingDirectory(this,
                                                        tr("Open Directory"),
                                                        "D:",
                                                        QFileDialog::ShowDirsOnly |
                                                        QFileDialog::DontResolveSymlinks);
    if(dirName.isEmpty()) {
        operationStatus->setText(tr("No Directory Name set."));
        return;
    }
    this->setWindowTitle(dirName);
    QDir directory(dirName);
    QStringList filters;
    filters<<"*.jpg"<<"*.bmp"<<"*.jpeg"<<"*.png";
    directory.setNameFilters(filters);
    if(!filesList.empty())
        filesList.clear();
    filesList = directory.entryList(QDir::AllEntries |
                                    QDir::NoDotAndDotDot |
                                    QDir::Hidden);  //获取目录下的所有文件
}
//自动ROI选择
void MainWindow::on_action_ROI_triggered()
{
    std::vector<int> result = sortedFileNames(filesList);
    operationStatus->setText(tr("Processing ROIs..."));
    BOOST_AUTO(pos,result.begin());
    for(; pos != result.end(); ++pos) {
        QCoreApplication::processEvents();
        QString absoluteFilePath = this->windowTitle() + "/" + QString::number(*pos) + ".jpg";
        qDebug()<<"filename="<< absoluteFilePath;
        cv::Mat oriMat = cv::imread(absoluteFilePath.toLatin1().constData());
        if(oriMat.empty())
            continue;
        rois = autoExtractROI(oriMat); //在图像中自动选择ROI
    }
    operationStatus->setText(tr("Done ROI."));
}
//BOG目标识别
void MainWindow::on_action_BOG_triggered()
{

}
//BP训练
//根据标记的样本提取对应类别系数块
void MainWindow::on_action_BPTrain_triggered()
{
    if(filesList.empty()) {
        QMessageBox::critical(this,tr(""),tr("Choose a valid image path first."),QMessageBox::Ok);
        return;
    }
    bp.createANN(22,10,2);  //22个输入单元，10个隐单元，2个输出单元

    std::vector<std::vector<double> > trainingData;
    std::vector<int> sampleTypes;

    BOOST_AUTO(pos,filesList.begin());
    for(; pos != filesList.end(); ++pos) {
        cv::Mat img = cv::imread((this->windowTitle() +
                                  "/" +
                                  (*pos)).toLatin1().constData(),
                                 0);    //读入的是灰度图
        //读取手工标记的样本
        cv::Mat markedSample = cv::imread((this->windowTitle() +
                                           "/drawing_output/" +
                                           (*pos)).toLatin1().constData());
        if(markedSample.empty() || markedSample.data == NULL) { //通常是图片路径设置不正确
            QMessageBox::critical(this,tr(""),tr("No valid image found."),QMessageBox::Ok);
            return;
        }
        for(int i = 0; i < img.rows; i += 8) {
            for(int j = 0; j < img.cols; j += 8) {
                cv::Mat imgROI(img,cv::Rect(j,i,8,8));   //获取8*8图像块，原来如此easy
                cv::Mat markedSampleROI(markedSample,cv::Rect(j,i,8,8));
                //对图片进行DCT变换，得到之字型系数块
                cv::Mat dctResult;
                imgROI.convertTo(imgROI,CV_32FC1);
                cv::dct(imgROI,dctResult);
                std::vector<double> zzCoeff;
                for(int i = 0; i < 8; ++i) {
                    zzCoeff.push_back(dctResult.at<double>(0,i));
                    if(i != 0 && i != 7)
                        zzCoeff.push_back(dctResult.at<double>(i,7-i));
                    zzCoeff.push_back(dctResult.at<double>(7,i));
                }
                trainingData.push_back(zzCoeff);
                //根据事先标记的信息确定样本类别
                int label = getBlockType(markedSampleROI);
                sampleTypes.push_back(label);
            }
        }
    }   //热身运动完毕
    bp.trainANN(trainingData,sampleTypes);  //正片开始
}
//BP测试
void MainWindow::on_action_BPTest_triggered()
{

}
//生成训练样本
//对labeled_train_sample中的图像画线并手工标记每个矩形块的类别
void MainWindow::on_action_3_triggered()
{
    std::vector<int> result = sortedFileNames(filesList);
    operationStatus->setText(tr("Processing..."));

    QDir dir(this->windowTitle());
    dir.mkdir("drawing_output");

    BOOST_AUTO(pos,result.begin());
    for(; pos != result.end(); ++pos) {
        QCoreApplication::processEvents();
        QString absoluteFilePath = this->windowTitle() + "/" + QString::number(*pos) + ".jpg";
        QString drawedAbsoluteFilePath = this->windowTitle() + "/drawing_output/" + QString::number(*pos) + ".jpg";
        //        qDebug()<<"filename="<< absoluteFilePath;
        cv::Mat oriMat = cv::imread(absoluteFilePath.toLatin1().constData(),0);
        if(oriMat.empty() || oriMat.data == NULL)
            continue;
        drawRectOnGrayMat(oriMat,8,8);
        cv::imwrite(drawedAbsoluteFilePath.toLatin1().constData(),oriMat);
    }
    operationStatus->setText(tr("Done."));
}

//        oriMat = cv::Mat_<double>(oriMat);
//将原始图像分为3个通道
//        cv::dct(oriMat,temp);
//        std::vector<cv::Mat> planes;
//        cv::split(oriMat,planes);
//        std::vector<cv::Mat> outplanes(planes.size());
//        std::cout << "  Individual input planes have type = "
//                  << planes[0].type() << std::endl;

//        for (size_t i = 0; i < planes.size(); i++)
//        {
//            planes[i].convertTo(planes[i], CV_32FC1);
//            cv::dct(planes[i], outplanes[i]);
//            viewMat(outplanes[i]);
//        }
//        std::cout << "  Individual  DCT  planes have type = "
//                  << outplanes[0].type() << std::endl;
//        // Now put the planes together into a single image
//        cv::Mat merged;
//        cv::merge(outplanes, merged);
//        std::cout << "Merged DCT image has type  = " << merged.type() << std::endl;
//        cv::imwrite(DCTAbsoluteFilePath.toLatin1().constData(),merged);
//        cv::imshow(DCTAbsoluteFilePath.toLatin1().constData(),merged);

//根据提取的ROI使用grabcut分割目标
void MainWindow::on_actionMean_shift_triggered()
{
    if(singleMat.empty() || singleMat.data == NULL)
        return;
    BOOST_AUTO(pos,rois.begin());
    for(int i = 1; pos != rois.end(); ++pos, ++i) {
        cv::Mat segResult,bgModel,fgModel;
        cv::grabCut(singleMat, segResult, (*pos),
                    bgModel, fgModel,
                    5, cv::GC_INIT_WITH_RECT);
        cv::imshow((QString::number(i) + ".jpg").toLatin1().constData(),segResult);
    }
}
//打开图片
void MainWindow::on_action_5_triggered()
{
    QString fileName = QFileDialog::getOpenFileName(this,
                                                    tr("Open Video"),".",
                                                    tr("Images (*.jpg, *.jpeg, *.png, * bmp)"));
    singleMat = cv::imread(fileName.toLatin1().constData());
    cV2QImage(singleMat,ui->scrollArea,ui->label);
}
